package com.steakliu.sun.server.netty;

import com.steakliu.sun.common.thread.ServerConcurrentThreadPool;
import com.steakliu.sun.invoker.api.Invoker;
import com.steakliu.sun.server.api.ServerConfig;
import com.steakliu.sun.server.api.ServerLocalServiceCaches;
import com.steakliu.sun.server.api.Server;
import com.steakliu.sun.server.netty.initializer.SunServerChannelInitializer;
import com.steakliu.sun.server.netty.manager.ServerChannelManager;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelOption;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.util.concurrent.DefaultEventExecutorGroup;
import io.netty.util.concurrent.EventExecutorGroup;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Map;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * 功能说明： Netty服务端
 * <p>
 * Original @Author: steakliu-刘牌, 2023-01-08  00:10
 * <p>
 * Copyright (C)2020-2022  steakliu All rights reserved.
 */
public class NettyServer implements Server {

    private final Logger LOGGER = LoggerFactory.getLogger(NettyServer.class);
    /**
     * 本地服务缓存
     */
    private final Map<String, ServerLocalServiceCaches> cacheServices;
    /**
     * 反射调用
     */
    private final Invoker invoker;
     /**
     * 服务端配置
     */
    private final ServerConfig serverConfig;
    /**
     * 并发线程池
     */
    private final ServerConcurrentThreadPool serverConcurrentThreadPool;

    public NettyServer(Map<String, ServerLocalServiceCaches> cacheServices, Invoker invoker, ServerConfig serverConfig, ServerConcurrentThreadPool serverConcurrentThreadPool) {
        this.cacheServices = cacheServices;
        this.invoker = invoker;
        this.serverConfig = serverConfig;
        this.serverConcurrentThreadPool = serverConcurrentThreadPool;
    }

    @Override
    public void startServer() {
        ServerBootstrap bootstrap = new ServerBootstrap();
        NioEventLoopGroup bossGroup = new NioEventLoopGroup(serverConfig.getBossGroupThreads());
        NioEventLoopGroup workGroup = new NioEventLoopGroup(serverConfig.getWorkGroupThreads());
        try {
            bootstrap.group(bossGroup, workGroup)
                    .channel(NioServerSocketChannel.class)
                    .childHandler(new SunServerChannelInitializer(cacheServices, invoker, serverConfig, serverConcurrentThreadPool))
                    .option(ChannelOption.SO_BACKLOG, 128)
                    .childOption(ChannelOption.SO_KEEPALIVE, true);
            ChannelFuture future = bootstrap.bind(serverConfig.getHost(), serverConfig.getPort()).sync();
            LOGGER.info("sun netty service started successfully, host:【{}】, port：【{}】", serverConfig.getHost(), serverConfig.getPort());
            future.channel().closeFuture().sync();
        } catch (Exception e) {
            LOGGER.info("sun netty service failed to start , host:【{}】, port：【{}】", serverConfig.getHost(), serverConfig.getPort());
        } finally {
            workGroup.shutdownGracefully();
            bossGroup.shutdownGracefully();
        }
    }
}
